use crate::resolver::cli_args::CliArgs;
use crate::resolver::history_struct::Version;
use crate::resolver::Resolver;
use serde_json::json;
use std::fs;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

fn upon_date_filter(value: i64, format: &str) -> String {
    let dt = chrono::DateTime::from_timestamp(value, 0).unwrap();
    dt.format(format).to_string()
}
fn upon_message_filter(value: &str) -> String {
    if let Some(idx) = value.find(": ") {
        return value[(idx + 2)..].to_string();
    }
    value.trim().to_string()
}
const TEMPLATE_CONTENT: &str = include_str!("../files/CHANGELOG.md");

impl Resolver {
    pub fn generate(&mut self) -> anyhow::Result<()> {
        let mut engine = upon::Engine::new();
        engine.add_template("source", TEMPLATE_CONTENT)?;
        engine.add_filter("date_filter", upon_date_filter);
        engine.add_filter("message_filter", upon_message_filter);
        let template_value = json!(self.history); // 将template转换为serde_json::Value
        let content = engine
            .template("source")
            .render(upon::value! {template: &template_value})
            .to_string()?;
        if let Some(output) = &self.cli_args.output {
            let parent = PathBuf::from(output);
            let parent = parent.parent().unwrap();
            fs::create_dir_all(parent)?;
            fs::write(output, content)?;
        } else {
            let path = &self.path;
            let path = path.join("CHANGELOG.md");
            fs::write(path, content)?;
        }
        Ok(())
    }
}
/// 生成版本号
pub fn generate_version(args: &CliArgs, versions: &mut Vec<Version>) -> anyhow::Result<()> {
    let mut iter = versions.iter_mut().peekable();
    //判断有没有第一个version
    if let Some(version) = iter.next() {
        //判断第一个版本是不是None
        if version.name != "None" {
            //如果第一个版本号不是None，那么：
            //不升级版本号，直接生成changelog
            return Ok(());
        }
        //判断有没有上一个version
        if let Some(last_version) = iter.peek() {
            //有下一个version，那么：
            //根据下一个version升级版本号，生成changelog
            generate_next_version(args, version, last_version);
        } else {
            //没有下一个version，那么：
            //将第一个版本号改为v1.0.0，生成changelog
            generate_first_version(args, versions);
        }
    } else {
        //如果没有第一个version，那么：
        //提交第一个版本v1.0.0，生成changelog
        generate_first_version(args, versions);
    }
    Ok(())
}
/// 生成第一个版本号
fn generate_first_version(args: &CliArgs, versions: &mut Vec<Version>) {
    let mut version = if let Some(v) = args.version.as_ref().or_else(|| args.version.as_ref()) {
        v.clone()
    } else {
        "v1.0.0".to_string()
    };
    let tag = get_tag(args);
    if tag.is_some() {
        //生成tag
        let tag = tag.unwrap();
        version = format!("{version}-{tag}.0");
    }
    if versions.len() == 0 {
        let now = SystemTime::now();
        let since_epoch = now.duration_since(UNIX_EPOCH).unwrap();
        let timestamp = since_epoch.as_secs() as i64;
        let first_version = Version {
            name: version,
            time: timestamp,
            sections: vec![],
        };
        versions.push(first_version);
    } else {
        versions[0].name = version;
    }
}
/// 根据规则生成最新版本号
///
/// 规则： https://www.conventionalcommits.org/zh-hans/
fn generate_next_version(args: &CliArgs, version: &mut Version, last_version: &Version) {
    if let Some(v) = args.version.as_ref().or_else(|| args.version.as_ref()) {
        version.name = v.to_owned();
        return;
    }
    let re = regex::Regex::new(r"v?(\d+)\.(\d+)\.(\d+)(?:-(\w+)\.(\d+))?").unwrap();
    let captures = re.captures(&last_version.name).unwrap();
    let mut major = captures.get(1).unwrap().as_str().parse::<u32>().unwrap();
    let mut minor = captures.get(2).unwrap().as_str().parse::<u32>().unwrap();
    let mut patch = captures.get(3).unwrap().as_str().parse::<u32>().unwrap();

    let tag = get_tag(args);
    if tag.is_some() {
        //生成tag
        let tag_info = captures.get(4).map(|m| {
            (
                m.as_str().to_string(),
                captures.get(5).unwrap().as_str().parse::<i32>().unwrap(),
            )
        });
        let tag_info = tag_info.map(|(tag, tag_patch)| (tag, tag_patch));
        let tag = tag.unwrap();
        if let Some(ti) = tag_info {
            let tag_patch = ti.1 + 1;
            version.name = format!("v{}.{}.{}-{}.{}", major, minor, patch, tag, tag_patch);
        } else {
            version.name = format!("v{}.{}.{}-{}.{}", major, minor, patch, tag, 0);
        }
        return;
    }

    if version.sections.iter().any(|s| s.section == "break") {
        //判断有没有break的提交
        major += 1;
        minor = 0;
        patch = 0;
    } else if version.sections.iter().any(|s| s.section == "feat") {
        //判断有没有feat的提交
        minor += 1;
        patch = 0;
    } else {
        //其它情况下patch+1
        // 本来是判断有没有fix的提交的，但是后来觉得还是patch+1的比较好，这个是原来的if判断条件：
        //if version.sections.iter().any(|s| s.section == "fix")
        patch += 1;
    }
    version.name = format!("v{}.{}.{}", major, minor, patch);
}
fn get_tag(args: &CliArgs) -> Option<String> {
    let tag = if let Some(t) = &args.tag {
        Some(t.to_owned())
    } else if args.beta {
        Some("beta".to_string())
    } else if args.alpha {
        Some("alpha".to_string())
    } else {
        None
    };
    tag
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::resolver::cli_args::CliArgs;
    use crate::utils::test_utils::{setup_with_commits_json, teardown_git};
    use std::path::PathBuf;

    #[test]
    fn test_generate() -> anyhow::Result<()> {
        let test_folder = setup_with_commits_json("tests/test_commits/test1.json")?;
        let mut args = CliArgs::new();
        args.path = Some(test_folder.to_string());
        let mut resolver = Resolver::init(args)?;
        // 解析git历史
        resolver.resolve()?;
        assert_eq!(5, resolver.history.versions.len());
        assert_eq!(0, resolver.history.versions[0].sections.len());
        resolver.handle()?;
        assert!(resolver.history.versions[1].sections[0]
            .section
            .contains("新功能"));
        resolver.generate()?;
        let buf = PathBuf::from(&test_folder).join("CHANGELOG.md");
        assert!(fs::exists(buf)?);
        teardown_git(&test_folder);
        Ok(())
    }

    #[test]
    fn test_output() -> anyhow::Result<()> {
        let test_folder = setup_with_commits_json("tests/test_commits/test1.json")?;
        let mut args = CliArgs::new();
        args.path = Some(test_folder.to_string());
        let buf = PathBuf::from(&test_folder)
            .join("test_output")
            .join("CHANGELOG.md");
        args.output = Some(buf.to_str().unwrap().to_string());
        let mut resolver = Resolver::init(args)?;
        // 解析git历史
        resolver.resolve()?;
        resolver.handle()?;
        resolver.generate()?;
        assert!(fs::exists(buf)?);
        teardown_git(&test_folder);
        Ok(())
    }
}
